#include "MessageHook.h"

typedef struct _GUI_PROCESS_INFO
{
    DWORD dwProcessId;
    HWND hWindow;
}GUI_PROCESS_INFO, * PGUI_PROCESS_INFO;

BOOL EnumWindowsProc(IN HWND hwnd, IN LPARAM lParam)
{
    BOOL bRet = TRUE;
    DWORD dwProcessId;
    PGUI_PROCESS_INFO lpGuiPsInfo = (PGUI_PROCESS_INFO)(lParam);

    GetWindowThreadProcessId(hwnd, &dwProcessId);

    if (dwProcessId == lpGuiPsInfo->dwProcessId && (::GetWindow(hwnd, GW_OWNER) == (HWND)0 && ::IsWindowVisible(hwnd)))
    {
        bRet = FALSE;
        lpGuiPsInfo->hWindow = hwnd;
    }

    return bRet;
}

BOOL MessageHook(DWORD dwId, PCSTR lpFunction, PCWCH lpBinary)
{
    BOOL bRet = FALSE;
    HMODULE hModule;
    HOOKPROC lpFunctionAddress;
    GUI_PROCESS_INFO GuiPsInfo = { 0 };
    DWORD dwThreadId;
    HHOOK hHook;

    do
    {
        hModule = LoadLibraryEx(lpBinary, nullptr, DONT_RESOLVE_DLL_REFERENCES);
        if (!hModule) break;

        lpFunctionAddress = (HOOKPROC)GetProcAddress(hModule, lpFunction);
        if (!lpFunctionAddress) break;

        GuiPsInfo.dwProcessId = dwId;
        bRet = EnumWindows(EnumWindowsProc, (LPARAM)&GuiPsInfo);
        if (!GuiPsInfo.hWindow) break;

        dwThreadId = GetWindowThreadProcessId(GuiPsInfo.hWindow, nullptr);
        if (!dwThreadId) break;

        hHook = SetWindowsHookEx(WH_KEYBOARD, lpFunctionAddress, hModule, dwThreadId);
        if (!hHook) break;

        bRet = TRUE;

    } while (FALSE);

    return bRet;
}
